/*
 * TMap Designer - A Thematic Map design software
 * Copyright (C) 2006 World Health Organization
 * http://www.who.int
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 */
package who.tmap.dao.impl;

import java.awt.geom.Point2D;
import java.io.File;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import org.jdom.Attribute;
import org.jdom.DataConversionException;
import org.jdom.Element;

import who.tmap.bo.BaseMap;
import who.tmap.bo.BizObject;
import who.tmap.bo.impl.BizObjectFactory;
import who.tmap.common.TMapException;
import who.tmap.dao.BaseMapDAO;
import who.tmap.dao.FileExtensions;
import who.tmap.dao.TMapDAOException;
import who.tmap.toolkit.dao.MapShapeDAO;
import who.tmap.toolkit.dao.MapShapeDAOFactory;
import who.tmap.toolkit.dao.PolygonShapeDAO;
import who.tmap.toolkit.impl.ShapeFileToBaseMapHelper;
import who.tmap.toolkit.shape.LabelShape;
import who.tmap.toolkit.shape.MapShape;
import who.tmap.toolkit.shape.MapShapes;
import who.tmap.toolkit.shape.PolygonShape;
import who.tmap.toolkit.shape.annotation.AnnotationShape;
import who.tmap.toolkit.shape.cdpointsymbol.CDPointSymbol;

/**
 * @author stl
 *
 * TODO To change the template for this generated type comment go to
 * Window - Preferences - Java - Code Style - Code Templates
 */
public class BaseMapDAOImpl extends BaseDAOImpl 
							implements BaseMapDAO {
 
    private static final String VERSION ="1.0";
    protected MapShapeDAOFactory msdf =MapShapeDAOFactory.getInstance();
    
    /**
     *	Package-visible only (enough for the factory)
     */
    BaseMapDAOImpl() {  
        super();
    }
    
    @SuppressWarnings("unchecked")
	public BizObject loadXml( Element elt ) throws TMapDAOException {
        BaseMap baseMap =null;
         
        if ( !isLinkedFile( elt ) ) {
	        try {       
		        baseMap = (BaseMap)bof.get( BizObjectFactory.BASE_MAP );
		        baseMap.setFile( null );
		        
		        List<MapShape> shapes =new ArrayList<MapShape>();
		        baseMap.setShapes( shapes );
		        
		        String version =elt.getAttributeValue("version");
		        
		        Element headerElt =elt.getChild( "Header" );
		        Element gbElt =headerElt.getChild( "GeographicBox" );
		        baseMap.setMinX( gbElt.getAttribute("xmin").getDoubleValue() );
		        baseMap.setMinY( gbElt.getAttribute("ymin").getDoubleValue() );
		        baseMap.setMaxX( gbElt.getAttribute("xmax").getDoubleValue() );
		        baseMap.setMaxY( gbElt.getAttribute("ymax").getDoubleValue() );
		        
		        baseMap.setDbaseJoinIdx( readDbaseJoinId( elt ) );
	
		        Iterator it =elt.getChildren( "Layer" ).iterator();
		        while( it.hasNext() ) {
		            Element layerElt =(Element)it.next();
		            
			        Iterator lit =layerElt.getChildren( "Polygon" ).iterator();
			        while( lit.hasNext() ) {
			            Element shapeElt =(Element)lit.next();
			            
		                MapShapeDAO dao =(MapShapeDAO)msdf.getDAO( MapShapes.POLYGON );
		                MapShape shape =dao.load( shapeElt );
			        
		                shapes.add( shape );
			        }
		        }
		        
	        } catch( Exception e ) {
		        throw new TMapDAOException( e );
	        }
        } else {
    	    Attribute linkElt =elt.getAttribute( "linkFile" ); 
    	    String fileName =linkElt.getValue();
    	    if ( fileName.toUpperCase().endsWith( FileExtensions.BASE_MAP_EXT.toUpperCase() ) ) {
    	    	baseMap =(BaseMap)loadLinkedFile( elt );
    	    } else {
    	    	try {
    	    		int dbasePolygonIdx =readDbaseJoinId( elt );
					
					baseMap =new ShapeFileToBaseMapHelper().convert( fileName, dbasePolygonIdx );
					
				} catch ( Exception e) {
					throw new TMapDAOException ( e );
				}
    	    }
        }
        
        return baseMap;    	
    }
    
    private int readDbaseJoinId( Element elt ) throws DataConversionException  {
    	int dbaseJoinId =-1;
    	
        Element dpiElt =elt.getChild( "DbaseJoinId" );
        if ( dpiElt != null ) {
        	dbaseJoinId =dpiElt.getAttribute( "idx" ).getIntValue();
        }
        
        return dbaseJoinId;
    }
    
    /**
     * Load a base map from a TMap xml file
     */
    public BizObject load( String fileName ) throws TMapDAOException {
         BaseMap baseMap =null;
        
        try {
	        Element rootElt =getRootElement( fileName );
	        
	        baseMap =(BaseMap)loadXml( rootElt );
	        baseMap.setFile( new File( fileName ) );
	        	        
        } catch( Exception e ) {
	        throw new TMapDAOException( e );
        }
        
        return baseMap;
    }   
    
	public Element saveXml(BizObject object) throws TMapDAOException {
        BaseMap baseMap =(BaseMap)object;
        List<MapShape> shapes =baseMap.getShapes();        
        
        Element rootElt =new Element( ROOT_ELT );
        rootElt.setAttribute( "version", VERSION );
        
        // Build header node
        Element headerElt =new Element( "Header" );
        rootElt.addContent( headerElt );
        Element gbElt =new Element( "GeographicBox" );
        headerElt.addContent( gbElt );
        gbElt.setAttribute( "xmin", String.valueOf( baseMap.getMinX() ) );
        gbElt.setAttribute( "ymin", String.valueOf( baseMap.getMinY() ) );
        gbElt.setAttribute( "xmax", String.valueOf( baseMap.getMaxX() ) );
        gbElt.setAttribute( "ymax", String.valueOf( baseMap.getMaxY() ) );
        
        saveDbaseJoinId( rootElt, baseMap.getDbaseJoinIdx() );
        
        // Layers
        Element layerElt =new Element( "Layer" );
        rootElt.addContent( layerElt );  
        
        MapShapeDAO dao;

        for( MapShape shape : shapes ) {
            
            if ( ! (shape instanceof AnnotationShape) && !( shape instanceof CDPointSymbol ) ) {
	            try {
	                dao =msdf.getDAO( shape.getType() );
	                
	                if ( shape instanceof PolygonShape ) {
	                	LabelShape labelShape =((PolygonShape)shape).getLabelShape();
	                	
	                	PolygonShapeDAO psDao =(PolygonShapeDAO)dao;
	                	psDao.setDistancePt( labelShape.getDistancePt() != null 
	                							? labelShape.getDistancePt()
	                							: new Point2D.Double(0,0) );
	                	psDao.setVisible( labelShape.isVisible() );
	                }
	            } catch (TMapException e1) {
	                throw new TMapDAOException( e1 );
	            }
	            
	            Element shapeElt =dao.save( shape );
	            layerElt.addContent( shapeElt );
            }
        }
        
        return rootElt;
	}
	
	public void saveDbaseJoinId( Element rootElt, int dbaseJoinIdx ) {
		
        Element djiElt =new Element( "DbaseJoinId" );
        rootElt.addContent( djiElt );
        djiElt.setAttribute( "idx", String.valueOf( dbaseJoinIdx ) );
        
	}

}
